/*
 * Copyright (c) 2010 Mathias Garbe <code@mathias-garbe.de>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "OnlineStatus.hpp"

namespace
{
    // Used by writeToMemoryCallback
    struct MemoryChunk {
        char *data;
        size_t size;
    };

    // This is the memory write callback for curls download
    static size_t writeToMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
    {
        size_t realsize = size * nmemb;
        struct MemoryChunk *mem = (struct MemoryChunk *)data;

        mem->data = (char*)realloc(mem->data, mem->size + realsize + 1);
        if (mem->data == NULL) {
            /* out of memory! */ 
            printf("not enough memory (realloc returned NULL)\n");
            exit(EXIT_FAILURE);
        }

        memcpy(&(mem->data[mem->size]), ptr, realsize);
        mem->size += realsize;
        mem->data[mem->size] = 0;

        Qt::QAppInstance()->processEvents(QEventLoop::AllEvents, 10);
        Qt::QAppInstance()->flush();

        return realsize;
    }
}

OnlineStatus::OnlineStatus()
{
    this->curl = curl_easy_init();
    if(!this->curl)
        throw std::runtime_error("curl could not be initialized.");
}

OnlineStatus::~OnlineStatus()
{
    if(this->curl)
        curl_easy_cleanup(this->curl);
}

void OnlineStatus::updateStatus(int gameID)
{
    struct MemoryChunk chunk;

    chunk.data = (char*)malloc(1);
    chunk.size = 0;

    QSettings settings;
    std::string nickname = settings.value("General/GameHandle", "").toString().toStdString();

    if(nickname == "")
    {
        this->onlinePlayers.clear();
        OnlinePlayer player("Set your nickname", -1, "-");
        this->onlinePlayers.push_back(player);
        return;
    }

    std::stringstream url;
    url << "http://cncnet.cnc-comm.com/qtclient/onlinestatus/onlineplayers.php?nick=" << nickname << "&gameid=" << gameID << "&version=" << _BUILD_VERSION;

    curl_easy_setopt(this->curl, CURLOPT_URL, url.str().c_str());
    curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, writeToMemoryCallback);
    curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void *)&chunk);
    curl_easy_setopt(this->curl, CURLOPT_USERAGENT, "CnCNet");
    curl_easy_setopt(this->curl, CURLOPT_TIMEOUT, 2);

    CURLcode code = curl_easy_perform(this->curl);

    if(code != 0)
        return;

    std::string data = chunk.data;

    if(chunk.data)
        free(chunk.data);

    // Clear online players
    
    this->onlinePlayers.clear();

    if(data.size() == 0)
        return;

    // Parse data
    std::vector<std::string> players = std::split(data, '\n');
    for(int i = 0; i < players.size(); i++)
    {
        std::vector<std::string> player_data = std::split(players[i], '\t');
        if(player_data.size() == 3)
        {
            OnlinePlayer player(player_data[0], atoi(player_data[1].c_str()), player_data[2]);
            this->onlinePlayers.push_back(player);
        }
    }
}

std::vector<OnlinePlayer> OnlineStatus::getOnlinePlayers()
{
    return this->onlinePlayers;
}
